package cn.javaxc.mvcwork.modules.notifier;
import cn.javaxc.mvcwork.controller.*;
import cn.javaxc.mvcwork.framework.actions.TModuleAction;
import cn.javaxc.mvcwork.framework.database.ConnectionPool;
import cn.javaxc.mvcwork.modules.admin.Contact;
import cn.javaxc.mvcwork.modules.file.*;
import cn.javaxc.mvcwork.modules.notifier.*;
import cn.javaxc.mvcwork.modules.site.*;
import cn.javaxc.mvcwork.util.common.*;

import cn.javaxc.mvcwork.util.io.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipOutputStream;
import java.util.Date;




public class Notifier extends ReportBuilder {

  private Map config = new HashMap();
  private ArrayList taskList = new ArrayList();
  private java.sql.Timestamp today = null;
  private java.sql.Timestamp yesterday = null;

  
  public final static String fs = System.getProperty("file.separator");
  public final static String lf = System.getProperty("line.separator");

  public Notifier() {
    //Get the time range for the reports
    Calendar calToday = Calendar.getInstance();
    today = new Timestamp(calToday.getTimeInMillis());

    Calendar calYesterday = Calendar.getInstance();
    calYesterday.set(Calendar.HOUR_OF_DAY, -25);
    yesterday = new Timestamp(calYesterday.getTimeInMillis());
  }

  public void setConfig(Map config) {
    this.config = config;
  }

  
  public static void main(String args[]) {
    if (args.length == 0) {
      System.out.println("Usage: Notifier [config file]");
      System.out.println("ExitValue: 2");
    }
    Notifier thisNotifier = new Notifier();
    thisNotifier.execute(args);
    System.exit(0);
  }


  
  public static void doTask(String args[]) {
    if (args.length == 0) {
      System.out.println("Usage: Notifier [config file]");
      System.out.println("ExitValue: 2");
    }
    Notifier thisNotifier = new Notifier();
    thisNotifier.execute(args);
    if (System.getProperty("DEBUG") != null) {
      System.out.println("ExitValue: 0");
    }
  }


  
  private void execute(String args[]) {
    String filename = args[0];
	if(System.getProperty("DEBUG")!=null)System.out.println(this.getClass().getName()+".execute "+Arrays.toString(args));
    if (args.length > 1) {
      //Task was specified on command line
      for (int taskCount = 1; taskCount < args.length; taskCount++) {
        this.getTaskList().add(args[taskCount]);
      }
    } else {
      //Temporary default list of tasks
      this.getTaskList().add(
          "cn.javaxc.mvcwork.apps.notifier.task.NotifyOpportunityOwners");
      this.getTaskList().add(
          "cn.javaxc.mvcwork.apps.notifier.task.NotifyCommunicationsRecipients");
      this.getTaskList().add("cn.javaxc.mvcwork.apps.notifier.task.NotifyCallOwners");
    }
    XMLUtils.loadConfig(filename, this.config);
    if (config.containsKey("FILELIBRARY")) {
      this.baseName = (String) this.config.get("gatekeeper.url");
      this.dbUser = (String) this.config.get("gatekeeper.user");
      this.dbPass = (String) this.config.get("gatekeeper.password");
      Connection db = null;
      try {
        SiteList siteList = SiteUtils.getSiteList(config);
        
        //Process each site
        Iterator i = siteList.iterator();
        while (i.hasNext()) {
          Site thisSite = (Site) i.next();
		  if (System.getProperty("DEBUG") != null) {
			  System.err.println(
				  thisSite.getDatabaseUrl()+" Notifier-> Start Date: " + yesterday.toString() + " Alert End Date: " + today.toString());
			}
          Class.forName(thisSite.getDatabaseDriver());
          db = DatabaseUtils.getConnection(
              thisSite.getDatabaseUrl(),
              thisSite.getDatabaseUsername(),
              thisSite.getDatabasePassword());
          this.baseName = thisSite.getSiteCode();
          //TODO: The intent is to move these all out as separate tasks and
          //have a TaskContext with an interface
          if (this.getTaskList().size() == 1) {
            Iterator classes = this.getTaskList().iterator();
            while (classes.hasNext()) {
              try {
                //Construct the object, which executes the task
                Class thisClass = Class.forName((String) classes.next());
                Class[] paramClass = new Class[]{Class.forName(
                    "java.sql.Connection"), HashMap.class, HashMap.class};
                Constructor constructor = thisClass.getConstructor(paramClass);
                Object[] paramObject = new Object[]{db, thisSite, this.getConfig()};
                Object theTask = constructor.newInstance(paramObject);
				if(System.getProperty("DEBUG")!=null)System.out.println(this.getClass().getName()+" theTask "+theTask);
                theTask = null;
              } catch (Exception e) {
                e.printStackTrace(System.out);
              }
            }
          }
          if (this.getTaskList().contains(
              "cn.javaxc.mvcwork.apps.notifier.task.NotifyOpportunityOwners")) {
			  if(System.getProperty("DEBUG")!=null)System.out.println(this.getClass().getName()+" buildOpportunityAlerts");
            this.output.append(this.buildOpportunityAlerts(db, thisSite));
          }
          if (this.getTaskList().contains(
              "cn.javaxc.mvcwork.apps.notifier.task.NotifyCommunicationsRecipients")) {
			  if(System.getProperty("DEBUG")!=null)System.out.println(this.getClass().getName()+" buildCommunications");
            this.output.append(this.buildCommunications(db, thisSite, null));
          }
          if (this.getTaskList().contains(
              "cn.javaxc.mvcwork.apps.notifier.task.NotifyCallOwners")) {
			  if(System.getProperty("DEBUG")!=null)System.out.println(this.getClass().getName()+" buildCallAlerts");
            this.output.append(this.buildCallAlerts(db, thisSite));
          }
          db.close();
        }
        if (System.getProperty("DEBUG") != null) {
          System.out.println(this.output.toString());
        }
        //java.util.Date end = new java.util.Date();
      } catch (Exception exc) {
        exc.printStackTrace(System.out);
        System.err.println("Notifier-> BuildReport Error: " + exc.toString());
      } finally {
        if (db != null) {
          try {
            db.close();
            db = null;
          } catch (Exception e) {
          }
        }
      }
    }
  }


  
  public String buildOpportunityAlerts(Connection db, Site siteInfo) throws SQLException {
    return "NoImplement";
  }


  
  public String buildCallAlerts(Connection db, Site siteInfo) throws SQLException {
	return "NoImplement";
  }


  
  public String buildCommunications(Connection db, Site siteInfo, ConnectionPool cp) throws Exception {
    String dbName = siteInfo.getDatabaseName();
    //Build the list
    CampaignList thisList = new CampaignList();
    thisList.setActiveRangeStart(yesterday);
    thisList.setActiveRangeEnd(today);
    thisList.setActive(CampaignList.TRUE);
    thisList.setReady(CampaignList.TRUE);
    thisList.setEnabled(CampaignList.TRUE);
    thisList.buildList(db);
    if (System.getProperty("DEBUG") != null) {
      if (thisList.size() > 0) {
        System.err.println(siteInfo.getDatabaseUrl()+" Notifier-> Active Campaigns: " + thisList.size());
      }
    }

    //Get this database's key
    String filePath = (String) config.get("FILELIBRARY") + fs + dbName + fs + "keys" + fs;
    File f = new File(filePath);
    f.mkdirs();
    PrivateString thisKey = new PrivateString(filePath + "survey2.key");

    //does the server support SSL
    String schema = "http";
    if ("true".equals((String) config.get("FORCESSL"))) {
      schema = "https";
    }
    //Process each campaign that is active and not processed
    Iterator i = thisList.iterator();
    int notifyCount = 0;
    while (i.hasNext()) {
      //Lock the campaign so the user cannot cancel, and so that another process
      //does not execute this campaign
      Campaign thisCampaign = (Campaign) i.next();
      NotificationUtils.sendCampaign(db,thisCampaign,null,false);
	  ++notifyCount;
    }
    return "Communications Report for " + start.toString() + lf + "Total Records: " + notifyCount;
  }


  
  private boolean outputFaxLog(ArrayList faxLog, Connection db, Site siteInfo) throws Exception {
    if (faxLog == null || faxLog.size() == 0) {
      return false;
    }
    if (System.getProperty("DEBUG") != null) {
      System.out.println("Notifier-> Outputting fax log");
    }
    PrintWriter out = null;
    String baseDirectory = (String) config.get("FILELIBRARY") + fs + "faxFiles";
    if (baseDirectory != null && !baseDirectory.equals("")) {
      if (!baseDirectory.endsWith(fs)) {
        baseDirectory += fs;
      }
      File dir = new File(baseDirectory);
      dir.mkdirs();
    }
    SimpleDateFormat formatter1 = new SimpleDateFormat("yyyyMMddHHmmss");
    String uniqueScript = formatter1.format(new java.util.Date());
    try {
      out = new PrintWriter(
          new BufferedWriter(
              new FileWriter(baseDirectory + "cfsfax" + uniqueScript + ".sh")));
      Iterator faxEntries = faxLog.iterator();
      while (faxEntries.hasNext()) {
        String uniqueId = formatter1.format(new java.util.Date());
        String thisEntry = (String) faxEntries.next();
        StringTokenizer st = new StringTokenizer(thisEntry, "|");
        String databaseName = st.nextToken();
        String messageId = st.nextToken();
        String faxNumber = st.nextToken();
        String contactId = null;
        if (st.hasMoreTokens()) {
          contactId = st.nextToken();
        }
        String enteredBy = null;
        if (st.hasMoreTokens()) {
          enteredBy = st.nextToken();
        }
        String recordId = null;
        if (st.hasMoreTokens()) {
          recordId = st.nextToken();
        }

        if (!"false".equals((String) config.get("FAXENABLED"))) {
          //Faxing is enabled
          String baseFilename = baseDirectory + "cfsfax" + uniqueId + messageId + "-" + faxNumber;
          //Must escape the & for Linux shell script
          String url = "http://" + siteInfo.getVirtualHost() + "/ProcessMessage.do?code=" + siteInfo.getSiteCode() + "\\&messageId=" + messageId + (contactId != null ? "\\&contactId=" + contactId : "");
//          if (HTTPUtils.convertUrlToPostscriptFile(url, baseFilename) == 1) {
//            continue;
//          }
          if (ImageUtils.convertPostscriptToTiffG3File(baseFilename) == 1) {
            continue;
          }
          File psFile = new File(baseFilename + ".ps");
          psFile.delete();

          //TODO: Create a wrapper class for HylaFax to simplify and reuse this

          //Info for log file which can be parsed later and queried against HylaFax
          out.println("echo \"### SendFax Script, transcript in .log file\"");
          out.println("echo \"# database:" + databaseName + "\"");
          out.println("echo \"# campaignId:" + recordId + "\"");
          out.println("echo \"# enteredBy:" + enteredBy + "\"");
          out.println("echo \"# contactId:" + contactId + "\"");
          //Fax command -- only removes file if sendfax is successful
          out.println(
              "sendfax -n " +
              "-h " + (String) config.get("FAXSERVER") + " " +
              "-d " + faxNumber + " " +
              baseFilename + ".tiff > " + baseDirectory + "cfsfax" + uniqueScript + ".log " +
              "&& rm " + baseFilename + ".tiff ");

        }
      }
    } catch (IOException e) {
      e.printStackTrace(System.out);
      return false;
    } finally {
      if (out != null) {
        out.close();
      }
    }
    try {
      java.lang.Process process = java.lang.Runtime.getRuntime().exec(
          "/bin/sh " + baseDirectory + "cfsfax" + uniqueScript + ".sh");
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }
    return true;
  }


  
  private boolean outputLetterLog(Campaign thisCampaign, Contact contactReport, String dbName, Connection db) throws Exception {
    return true;
  }


  
  public String generateCFSUrl(Site siteInfo, String url) {
    String schema = "http";
    if ("true".equals((String) config.get("FORCESSL"))) {
      schema = "https";
    }
    return ("<a href=\"" + schema + "://" + siteInfo.getVirtualHost() + "/" + url + "\">" +
        "View in Fumine CRM" +
        "</a>");
  }

  public String generateLink(Site siteInfo, String url) {
    String schema = "http";
    if ("true".equals((String) config.get("FORCESSL"))) {
      schema = "https";
    }
    return (schema + "://" + siteInfo.getVirtualHost() + "/" + url);
  }


  
  public ArrayList getTaskList() {
    return taskList;
  }


  
  public Map getConfig() {
    return config;
  }
}
